using Microsoft.Extensions.Logging;
using System.Reflection;
using Uantek.Device.Communication.Protocols.Interfaces;
using Uantek.Model.Mas;

namespace Uantek.Device.Communication.Utilities
{
    /// <summary>
    /// 驱动动态加载器
    /// </summary>
    public class DriverLoader
    {
        /// <summary>
        /// 日志记录器
        /// </summary>
        private readonly ILogger<DriverLoader>? _logger;

        /// <summary>
        /// 已加载的程序集缓存
        /// </summary>
        private readonly Dictionary<string, Assembly> _assemblyCache = new();

        /// <summary>
        /// 已加载的驱动类型缓存
        /// </summary>
        private readonly Dictionary<string, Type> _driverTypeCache = new();

        /// <summary>
        /// 驱动实例缓存
        /// </summary>
        private readonly Dictionary<string, object> _driverInstanceCache = new();

        /// <summary>
        /// 缓存锁
        /// </summary>
        private readonly object _cacheLock = new object();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="logger">日志记录器</param>
        public DriverLoader(ILogger<DriverLoader>? logger = null)
        {
            _logger = logger;
        }

        /// <summary>
        /// 加载驱动程序集
        /// </summary>
        /// <param name="assemblyPath">程序集路径</param>
        /// <returns>加载结果</returns>
        public bool LoadAssembly(string assemblyPath)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(assemblyPath))
                {
                    _logger?.LogWarning("程序集路径为空");
                    return false;
                }

                if (!File.Exists(assemblyPath))
                {
                    _logger?.LogWarning("程序集文件不存在: {AssemblyPath}", assemblyPath);
                    return false;
                }

                lock (_cacheLock)
                {
                    // 检查是否已经加载
                    var assemblyName = Path.GetFileNameWithoutExtension(assemblyPath);
                    if (_assemblyCache.ContainsKey(assemblyName))
                    {
                        _logger?.LogDebug("程序集已经加载: {AssemblyName}", assemblyName);
                        return true;
                    }

                    // 加载程序集
                    var assembly = Assembly.LoadFrom(assemblyPath);
                    _assemblyCache[assemblyName] = assembly;

                    _logger?.LogInformation("程序集加载成功: {AssemblyName}, 路径: {AssemblyPath}", assemblyName, assemblyPath);
                    return true;
                }
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "加载程序集时发生异常: {AssemblyPath}", assemblyPath);
                return false;
            }
        }

        /// <summary>
        /// 加载驱动类型
        /// </summary>
        /// <param name="assemblyName">程序集名称</param>
        /// <param name="typeName">类型名称</param>
        /// <returns>驱动类型</returns>
        public Type? LoadDriverType(string assemblyName, string typeName)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(assemblyName) || string.IsNullOrWhiteSpace(typeName))
                {
                    _logger?.LogWarning("程序集名称或类型名称为空");
                    return null;
                }

                lock (_cacheLock)
                {
                    var cacheKey = $"{assemblyName}.{typeName}";

                    // 检查缓存
                    if (_driverTypeCache.TryGetValue(cacheKey, out var cachedType))
                    {
                        _logger?.LogDebug("驱动类型已缓存: {CacheKey}", cacheKey);
                        return cachedType;
                    }

                    // 获取程序集
                    if (!_assemblyCache.TryGetValue(assemblyName, out var assembly))
                    {
                        _logger?.LogWarning("程序集未加载: {AssemblyName}", assemblyName);
                        return null;
                    }

                    // 查找类型
                    var type = assembly.GetType(typeName);
                    if (type == null)
                    {
                        // 尝试通过部分名称匹配
                        var types = assembly.GetTypes();
                        type = types.FirstOrDefault(t => t.Name.Equals(typeName, StringComparison.OrdinalIgnoreCase) ||
                                                        t.FullName?.EndsWith($".{typeName}", StringComparison.OrdinalIgnoreCase) == true);
                    }

                    if (type == null)
                    {
                        _logger?.LogWarning("在程序集中未找到类型: {AssemblyName}.{TypeName}", assemblyName, typeName);
                        return null;
                    }

                    // 缓存类型
                    _driverTypeCache[cacheKey] = type;

                    _logger?.LogInformation("驱动类型加载成功: {AssemblyName}.{TypeName}", assemblyName, typeName);
                    return type;
                }
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "加载驱动类型时发生异常: {AssemblyName}.{TypeName}", assemblyName, typeName);
                return null;
            }
        }

        /// <summary>
        /// 创建驱动实例
        /// </summary>
        /// <param name="assemblyName">程序集名称</param>
        /// <param name="typeName">类型名称</param>
        /// <param name="parameters">构造参数</param>
        /// <returns>驱动实例</returns>
        public object? CreateDriverInstance(string assemblyName, string typeName, params object[] parameters)
        {
            try
            {
                var type = LoadDriverType(assemblyName, typeName);
                if (type == null)
                {
                    return null;
                }

                // 创建实例
                var instance = Activator.CreateInstance(type, parameters);
                if (instance == null)
                {
                    _logger?.LogWarning("创建驱动实例失败: {AssemblyName}.{TypeName}", assemblyName, typeName);
                    return null;
                }

                _logger?.LogInformation("驱动实例创建成功: {AssemblyName}.{TypeName}", assemblyName, typeName);
                return instance;
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "创建驱动实例时发生异常: {AssemblyName}.{TypeName}", assemblyName, typeName);
                return null;
            }
        }

        /// <summary>
        /// 创建协议驱动实例
        /// </summary>
        /// <param name="assemblyName">程序集名称</param>
        /// <param name="typeName">类型名称</param>
        /// <param name="parameters">构造参数</param>
        /// <returns>协议驱动实例</returns>
        public IDeviceProtocol? CreateProtocolInstance(string assemblyName, string typeName, params object[] parameters)
        {
            try
            {
                var instance = CreateDriverInstance(assemblyName, typeName, parameters);
                
                if (instance is IDeviceProtocol protocol)
                {
                    _logger?.LogInformation("协议驱动实例创建成功: {AssemblyName}.{TypeName}", assemblyName, typeName);
                    return protocol;
                }

                _logger?.LogWarning("驱动实例不实现IDeviceProtocol接口: {AssemblyName}.{TypeName}", assemblyName, typeName);
                return null;
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "创建协议驱动实例时发生异常: {AssemblyName}.{TypeName}", assemblyName, typeName);
                return null;
            }
        }

        /// <summary>
        /// 创建传输驱动实例
        /// </summary>
        /// <param name="assemblyName">程序集名称</param>
        /// <param name="typeName">类型名称</param>
        /// <param name="parameters">构造参数</param>
        /// <returns>传输驱动实例</returns>
        public ICommunicationTransport? CreateTransportInstance(string assemblyName, string typeName, params object[] parameters)
        {
            try
            {
                var instance = CreateDriverInstance(assemblyName, typeName, parameters);
                
                if (instance is ICommunicationTransport transport)
                {
                    _logger?.LogInformation("传输驱动实例创建成功: {AssemblyName}.{TypeName}", assemblyName, typeName);
                    return transport;
                }

                _logger?.LogWarning("驱动实例不实现ICommunicationTransport接口: {AssemblyName}.{TypeName}", assemblyName, typeName);
                return null;
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "创建传输驱动实例时发生异常: {AssemblyName}.{TypeName}", assemblyName, typeName);
                return null;
            }
        }

        /// <summary>
        /// 调用驱动方法
        /// </summary>
        /// <param name="instance">驱动实例</param>
        /// <param name="methodName">方法名称</param>
        /// <param name="parameters">方法参数</param>
        /// <returns>方法返回值</returns>
        public object? InvokeDriverMethod(object instance, string methodName, params object[] parameters)
        {
            try
            {
                if (instance == null)
                {
                    _logger?.LogWarning("驱动实例为空");
                    return null;
                }

                if (string.IsNullOrWhiteSpace(methodName))
                {
                    _logger?.LogWarning("方法名称为空");
                    return null;
                }

                var type = instance.GetType();
                var method = type.GetMethod(methodName);

                if (method == null)
                {
                    // 尝试查找带参数的方法
                    var parameterTypes = parameters?.Select(p => p?.GetType()).ToArray() ?? Array.Empty<Type>();
                    method = type.GetMethod(methodName, parameterTypes!);
                }

                if (method == null)
                {
                    _logger?.LogWarning("在类型中未找到方法: {TypeName}.{MethodName}", type.Name, methodName);
                    return null;
                }

                var result = method.Invoke(instance, parameters);
                
                _logger?.LogDebug("驱动方法调用成功: {TypeName}.{MethodName}", type.Name, methodName);
                return result;
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "调用驱动方法时发生异常: {MethodName}", methodName);
                return null;
            }
        }

        /// <summary>
        /// 根据设备参数创建驱动实例
        /// </summary>
        /// <param name="parameter">设备参数</param>
        /// <param name="additionalParameters">额外的构造参数</param>
        /// <returns>驱动实例</returns>
        public object? CreateDriverFromParameter(MasEquipmentParameter parameter, params object[] additionalParameters)
        {
            try
            {
                if (parameter == null)
                {
                    _logger?.LogWarning("设备参数为空");
                    return null;
                }

                if (string.IsNullOrWhiteSpace(parameter.ProgramName) || string.IsNullOrWhiteSpace(parameter.DeviceName))
                {
                    _logger?.LogWarning("设备参数中程序集名称或设备名称为空");
                    return null;
                }

                _logger?.LogDebug("根据设备参数创建驱动实例: {ProgramName}.{DeviceName}", parameter.ProgramName, parameter.DeviceName);

                return CreateDriverInstance(parameter.ProgramName, parameter.DeviceName, additionalParameters);
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "根据设备参数创建驱动实例时发生异常");
                return null;
            }
        }

        /// <summary>
        /// 调用设备参数指定的方法
        /// </summary>
        /// <param name="instance">驱动实例</param>
        /// <param name="parameter">设备参数</param>
        /// <param name="methodParameters">方法参数</param>
        /// <returns>方法返回值</returns>
        public object? InvokeParameterMethod(object instance, MasEquipmentParameter parameter, params object[] methodParameters)
        {
            try
            {
                if (parameter == null || string.IsNullOrWhiteSpace(parameter.MethodName))
                {
                    _logger?.LogWarning("设备参数或方法名称为空");
                    return null;
                }

                _logger?.LogDebug("调用设备参数指定的方法: {MethodName}", parameter.MethodName);

                return InvokeDriverMethod(instance, parameter.MethodName, methodParameters);
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "调用设备参数指定的方法时发生异常");
                return null;
            }
        }

        /// <summary>
        /// 获取缓存的实例
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <returns>缓存的实例</returns>
        public object? GetCachedInstance(string key)
        {
            lock (_cacheLock)
            {
                return _driverInstanceCache.TryGetValue(key, out var instance) ? instance : null;
            }
        }

        /// <summary>
        /// 缓存实例
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <param name="instance">实例</param>
        public void CacheInstance(string key, object instance)
        {
            lock (_cacheLock)
            {
                _driverInstanceCache[key] = instance;
                _logger?.LogDebug("实例已缓存: {Key}", key);
            }
        }

        /// <summary>
        /// 移除缓存的实例
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <returns>是否移除成功</returns>
        public bool RemoveCachedInstance(string key)
        {
            lock (_cacheLock)
            {
                var removed = _driverInstanceCache.Remove(key);
                if (removed)
                {
                    _logger?.LogDebug("实例已从缓存中移除: {Key}", key);
                }
                return removed;
            }
        }

        /// <summary>
        /// 清空所有缓存
        /// </summary>
        public void ClearCache()
        {
            lock (_cacheLock)
            {
                // 释放实例缓存中的资源
                foreach (var kvp in _driverInstanceCache)
                {
                    if (kvp.Value is IDisposable disposable)
                    {
                        try
                        {
                            disposable.Dispose();
                        }
                        catch (Exception ex)
                        {
                            _logger?.LogWarning(ex, "释放缓存实例时发生异常: {Key}", kvp.Key);
                        }
                    }
                }

                _driverInstanceCache.Clear();
                _driverTypeCache.Clear();
                _assemblyCache.Clear();

                _logger?.LogInformation("所有缓存已清空");
            }
        }

        /// <summary>
        /// 获取加载的程序集信息
        /// </summary>
        /// <returns>程序集信息</returns>
        public Dictionary<string, Assembly> GetLoadedAssemblies()
        {
            lock (_cacheLock)
            {
                return new Dictionary<string, Assembly>(_assemblyCache);
            }
        }

        /// <summary>
        /// 获取加载的驱动类型信息
        /// </summary>
        /// <returns>驱动类型信息</returns>
        public Dictionary<string, Type> GetLoadedDriverTypes()
        {
            lock (_cacheLock)
            {
                return new Dictionary<string, Type>(_driverTypeCache);
            }
        }

        /// <summary>
        /// 获取缓存的实例信息
        /// </summary>
        /// <returns>实例信息</returns>
        public Dictionary<string, object> GetCachedInstances()
        {
            lock (_cacheLock)
            {
                return new Dictionary<string, object>(_driverInstanceCache);
            }
        }

        /// <summary>
        /// 获取统计信息
        /// </summary>
        /// <returns>统计信息</returns>
        public Dictionary<string, object> GetStatistics()
        {
            lock (_cacheLock)
            {
                return new Dictionary<string, object>
                {
                    ["LoadedAssembliesCount"] = _assemblyCache.Count,
                    ["LoadedDriverTypesCount"] = _driverTypeCache.Count,
                    ["CachedInstancesCount"] = _driverInstanceCache.Count,
                    ["LoadedAssemblies"] = _assemblyCache.Keys.ToArray(),
                    ["LoadedDriverTypes"] = _driverTypeCache.Keys.ToArray(),
                    ["CachedInstanceKeys"] = _driverInstanceCache.Keys.ToArray()
                };
            }
        }
    }
}